package org.example.chat.controller;

import org.example.chat.dao.ChatMessageRepository;
import org.example.chat.entity.ChatMessage;
import org.example.chat.utils.CommonUtils;
import org.example.chat.utils.SpringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationContext;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import sun.misc.BASE64Decoder;
import sun.misc.BASE64Encoder;

import javax.servlet.ServletOutputStream;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.*;
import java.net.HttpURLConnection;
import java.net.URL;
import java.net.URLEncoder;
import java.nio.charset.StandardCharsets;
import java.time.LocalDateTime;
import java.util.*;
import java.util.zip.ZipEntry;
import java.util.zip.ZipException;
import java.util.zip.ZipOutputStream;

@RestController
@RequestMapping("/test")
public class TestController {


    /**
     * 图像下载接口， 返回base64编码的图像信息
     *
     * @param response
     * @param imgType
     * @throws IOException
     */
    @GetMapping("/getImage")
    public void imageDownloadServer(HttpServletResponse response, String imgType) throws IOException {
        response.setContentType("text/plain");
        ServletOutputStream outputStream = response.getOutputStream();
        BASE64Encoder encoder = new BASE64Encoder();
        ByteArrayOutputStream bos = new ByteArrayOutputStream();
        File file = null;
        if ("F".equals(imgType)) {
            file = new File("C:\\Users\\cheva\\Desktop\\票样\\1.jpg");
        } else {
            file = new File("C:\\Users\\cheva\\Desktop\\票样\\2.jpg");
        }
        InputStream fis = new FileInputStream(file);
        int len = -1;
        byte[] buff = new byte[1024];
        while ((len = fis.read(buff)) != -1) {
            bos.write(buff, 0, len);
        }
        bos.flush();
        String base64 = encoder.encode(bos.toByteArray());
        fis.close();
        bos.close();
        outputStream.write(base64.getBytes(StandardCharsets.UTF_8));
        outputStream.flush();
        outputStream.close();
    }


    /**
     * 以附件的形式下载到客户端
     * @param request
     * @param response
     */
    @GetMapping("/download")
    public void dowload(HttpServletRequest request, HttpServletResponse response) {
        ByteArrayOutputStream bos = null;
        ZipOutputStream zipOutputStream = null;
        String outName = "my.zip";

        // 1. 向ZipOutputStream中写入数据。 流的走向： 数据字节 -> ZipOutputStream -> ByteArrayOutputStream
        // 注意： 在向ZipOutputStream中写完数据后，必须马上关闭ZipOutputStream，否则zip文件会损坏
        /**
         * 如下代码下载的zip文件会损坏
         * try {
         *             response.setContentType("application/zip");
         *             response.addHeader("Content-Disposition", "attachment;fileName=" + URLEncoder.encode(outName, "UTF-8"));
         *             bos = new ByteArrayOutputStream();
         *             zipOutputStream = new ZipOutputStream(bos);
         *             packageZipStream("0011", zipOutputStream);
         *             outputStream = response.getOutputStream();
         *             outputStream.write(bos.toByteArray());
         *         } catch (Exception e) {
         *             e.printStackTrace();
         *         } finally {
         *             if (zipOutputStream != null) {
         *                 try {
         *                     zipOutputStream.close();
         *                 } catch (Exception e) {
         *                     System.out.println("流关闭异常");
         *                 }
         *             }
         *             if (bos != null) {
         *                 try {
         *                     bos.close();
         *                 } catch (Exception e) {
         *                     System.out.println("流关闭异常");
         *                 }
         *             }
         *         }
         *   原因在于在使用respose输出字节数组的时候，zipoutputstream还没有关闭，导致文件损坏，代码应该如下
         */

        try {
            bos = new ByteArrayOutputStream();
            zipOutputStream = new ZipOutputStream(bos);
            for (int i = 0; i < 100; i++) {
                packageZipStream("0011" + i, zipOutputStream);
            }
        } catch (Exception e) {
            response.setContentType("text/html");
            response.setCharacterEncoding("UTF-8");
            try {
                ServletOutputStream os = response.getOutputStream();
                os.write(e.getMessage().getBytes());
                os.flush();
            } catch (IOException ioException) {
                ioException.printStackTrace();
            }
        } finally {
            // 注意: 像这种一层套一层的包装流，关闭顺序一定是先关闭外层包装流，然后再关闭内层的流，否则会文件损坏，而且在关闭外层流的时候会报流已经关闭异常
            if (zipOutputStream != null) {
                try {
                    zipOutputStream.close();
                } catch (Exception e) {
                    System.out.println("zip输出流关闭异常");
                }
            }
            if (bos != null) {
                try {
                    bos.close();
                } catch (Exception e) {
                    System.out.println("流关闭异常");
                }
            }
        }

        // 2. 响应数据
        try {
            response.setContentType("application/zip");
            response.addHeader("Content-Disposition", "attachment;fileName=" + URLEncoder.encode(outName, "UTF-8"));
            byte[] out = bos.toByteArray();
            response.setHeader("Content-Length", String.valueOf(out.length));
            ServletOutputStream outputStream = response.getOutputStream();
            outputStream.write(out);
            outputStream.flush();
        } catch (Exception e) {
            e.printStackTrace();
        }
    }


    /**
     * 下载到服务器本地文件夹
     * @param response
     */
    @GetMapping("/downloadLoc")
    public void downloadLoc(HttpServletResponse response) {
        FileOutputStream fis = null;
        ZipOutputStream zipOutputStream = null;
        try {
            File file = new File("D:\\Compressed\\my.zip");

            if (!file.getParentFile().exists()) {
                file.getParentFile().mkdir();
            }
            fis = new FileOutputStream(file);
            zipOutputStream = new ZipOutputStream(fis);
            packageZipStream("0011", zipOutputStream);
        } catch (Exception e) {
            response.setContentType("text/html");
            response.setCharacterEncoding("UTF-8");
            try {
                ServletOutputStream os = response.getOutputStream();
                os.write(e.getMessage().getBytes());
                os.flush();
            } catch (IOException ioException) {
                ioException.printStackTrace();
            }
        } finally {
            if (zipOutputStream != null) {
                try {
                    zipOutputStream.close();
                } catch (Exception e) {
                    System.out.println("流关闭异常");
                }
            }
            if (fis != null) {
                try {
                    fis.close();
                } catch (Exception e) {
                    System.out.println("流关闭异常");
                }
            }
        }
    }


    /**
     * 请求图片服务获取图像并写入到zip输出流中
     * @param imgId
     * @param zos
     */
    private void packageZipStream(String imgId, ZipOutputStream zos) {
        String path = null;
        try {
            if (zos == null || imgId == null) {
                return;
            }
            // 1.  向zip输出流写入文件（ZipEntry）, 如果有多个就循环下面五行代码。 注意： 如果文件重名，会ZipOutputStream会抛出ZipException
            path = imgId + File.separator + "正面.jpg";
            zos.putNextEntry(new ZipEntry(path));
            // 获取要写入ZipEntry的内容
            byte[] data = downloadImageFromURL("http://localhost:8098/chat-server/test/getImage?imgType=F");
            zos.write(data, 0, data.length);
            zos.closeEntry();

            path = imgId + File.separator + "反面.jpg";
            zos.putNextEntry(new ZipEntry(path));
            data = downloadImageFromURL("http://localhost:8098/chat-server/test/getImage?imgType=B");
            zos.write(data, 0, data.length);
            zos.closeEntry();
        } catch (Exception e) {
                if (e instanceof ZipException) {
                    throw new RuntimeException(path + "重名,只进行一次下载处理");
                } else {
                    throw new RuntimeException(e.getMessage());
                }

        }
    }


    /**
     * java HttpURLConnection作为客户端下载图像
     * @param urlPath
     * @return
     */
    private byte[] downloadImageFromURL(String urlPath) {
        HttpURLConnection conn = null;
        InputStream is = null;
        byte[] data = null;
        ByteArrayOutputStream bos = new ByteArrayOutputStream();
        try {
            URL url = new URL(urlPath);
            conn = (HttpURLConnection) url.openConnection();
            conn.setRequestMethod("GET");
            conn.setConnectTimeout(6000);
            conn.setDoInput(true);
            is = conn.getInputStream();
            if (conn.getResponseCode() == 200) {
                // 读取响应的输入流到字节输出流
                byte[] buff = new byte[1024];
                int len = -1;
                while ((len = is.read(buff)) != -1) {
                    bos.write(buff, 0, len);
                }
                bos.flush();
                data = bos.toByteArray();
                BASE64Decoder decoder = new BASE64Decoder();
                data = decoder.decodeBuffer(new String(data));
            } else {
                data = null;
            }
        } catch (Exception e) {
                throw new RuntimeException("连接服务器异常");

        } finally {
            if (is != null) {
                try {
                    is.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }

            if (bos != null) {
                try {
                    bos.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
        return data;
    }

    @GetMapping("/test9")
    public void test9() {
        ApplicationContext applicationContext = SpringUtils.getApplicationContext();
        System.out.println(applicationContext);
    }

    @Autowired
    private ChatMessageRepository chatMessageRepository;

    @GetMapping("/test10")
    public void test10() {
        ChatMessage chatMessage = new ChatMessage();
        chatMessage.setId("123213");
        chatMessage.setSendUserId("sada");
        chatMessage.setReceiveUserId("ss");
        chatMessage.setSignFlag(0);
        chatMessage.setCreateTime(LocalDateTime.now());
        ChatMessage chatMessage1 = new ChatMessage();
        chatMessage1.setId("12");
        chatMessage1.setSendUserId("sada");
        chatMessage1.setReceiveUserId("ss");
        chatMessage1.setSignFlag(0);
        chatMessage1.setCreateTime(LocalDateTime.now());
        List<ChatMessage> list = new ArrayList<>();
        list.add(chatMessage);
        list.add(chatMessage1);
        chatMessageRepository.saveAll(list);
    }

    @GetMapping("/test11")
    public void test11() {
        String[] ids = new String[] {"123213", "12"};
        int rows = chatMessageRepository.batchUpdateSignFlag(ids);
        System.out.println(rows);
    }

    @GetMapping("/test13")
    public void test13(String water) {
        CommonUtils.addWaterForImage("C:\\Users\\cheva\\Desktop\\file\\1.jpg", "C:\\Users\\cheva\\Desktop\\file\\2.jpg", water);
    }

    @GetMapping("/test14")
    public void test14(HttpServletRequest request) {
        String water = request.getParameter("water");
        System.out.println(water);
    }


    public static void main(String[] args) {
        // 配置项
        String imgIdsFilePath = "C:\\Users\\cheva\\Desktop\\11.txt";

        File imgIdsFile = null;
        FileInputStream fis = null;
        InputStreamReader isr = null;
        BufferedReader br  = null;
        try {
            // 1. 读取图像id文件
            imgIdsFile = new File(imgIdsFilePath);
            fis = new FileInputStream(imgIdsFile);
            isr = new InputStreamReader(fis);
            br  = new BufferedReader(isr);
            Map<String,List<String>> map = new HashMap<String, List<String>>();
            String[] split = null;
            while (true) {
                String line = br.readLine();
                if (line == null || line.length() == 0) {
                    break;
                }
                if (line == null) {
                    continue;
                }
                split = line.split("&&");
                if (split == null || split.length != 2) {
                    continue;
                }
                List<String> imgs = map.get(split[0]);
                if (imgs == null) {
                    imgs = new ArrayList<String>();
                    map.put(split[0], imgs);
                }
                imgs.add(split[1]);
            }

            // 2. 下载文件
            Set<String> keys = map.keySet();
            if (keys == null) {
                return;
            }
            Iterator<String> iterator = keys.iterator();
            while (iterator.hasNext()) {
                String key = iterator.next();
                String downloadLocation = "C:\\Users\\cheva\\Desktop\\昆明" + File.separator + key;
                List<String> imgIds = map.get(key);
                if (imgIds == null) {
                    continue;
                }
                for (int i = 0; i < imgIds.size(); i++) {
                    String imgId = imgIds.get(i);
                    String imgName = key + (i + 1);
                    String watermark = ".";
//                    String addressF = "http://132.147.252.249:9092/XWJ_CM/CDownloadImg.do?sequenceid=" + imgId + "&transmit=image&watermark=" + URLEncoder.encode(watermark, "UTF-8") + "&filetype=F";
//                    String addressF = "http://132.147.252.249:9092/XWJ_CM/CDownloadImg.do?sequenceid=" + imgId + "&transmit=image&watermark=" + URLEncoder.encode(watermark, "UTF-8") + "&filetype=F";
                    String addressB = "http://localhost:8098/chat-server/test/getImage?imgType=F";
                    downloadFromUrl(addressB, downloadLocation + File.separator + imgName + "_B.png");
                }
            }
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            if (br != null) {
                try {
                    br.close();
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }

            if (isr != null) {
                try {
                    isr.close();
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }

            if (fis != null) {
                try {
                    fis.close();
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }
        }
    }

    private static void downloadFromUrl(String address, String downloadLocation) {
        HttpURLConnection conn = null;
        InputStream is = null;
        FileOutputStream fos = null;
        try {
            URL url = new URL(address);
            conn = (HttpURLConnection) url.openConnection();
            conn.setRequestMethod("GET");
            conn.setConnectTimeout(6000);
            conn.setDoInput(true);
            is = conn.getInputStream();
            if (conn.getResponseCode() == 200) {
                int i = downloadLocation.lastIndexOf(File.separator);
                String parent = downloadLocation.substring(0,i);
                File file = new File(parent);
                if (!file.exists()) {
                    file.mkdirs();
                }
                fos = new FileOutputStream(downloadLocation);
                // 读取响应的输入流到字节输出流
                byte[] buff = new byte[1024];
                int len = -1;
                while ((len = is.read(buff)) != -1) {
                    fos.write(buff, 0, len);
                }
                fos.flush();
            }
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            if (fos != null) {
                try {
                    fos.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }

            if (is != null) {
                try {
                    is.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
            conn.disconnect();
        }
    }
}


